//@author A0088498A
package logic;

import gui.IUserInterface;
import hirondelle.date4j.DateTime;

import java.util.HashMap;

import common.AttributeType;
import common.CommandType;
import common.DateHelper;
import common.Task;
import common.TaskStatus;
import common.TaskType;

import memory.Database;

/**
 * Block command handler provides the implementation of the Block command <br/>
 * Block command will create a "dummy task" with status "blocked" and type
 * "timed" (that means the startingTime and endingTime fields must be provided
 * by users)<br/>
 * Task with "blocked" status cannot collide with other tasks. <br/>
 * <br/>
 * <b>Command Syntax:</b> <br/>
 * <b>block</b> -name <i>task_name</i> -from <i>starting_time</i> -to
 * <i>ending_time</i> <br/>
 * <i>Note: name, from and to fields are compulsory </i><br/>
 *  
 */

public class BlockCommandHandler extends CommandHandler {
	private final String SYNTAX_ERROR = "Block Command syntax error. Press F10 for help\n";
	private final String BLOCK_SUCCESSFUL = "\n\nThe time slot is now block!\n%1$s ";
	private final String BLOCK_ERROR = "\n\nError occured while deleting %1$s";
	private final String CREATE_OR_COLLISION_EXIST = "\n\n%1$s exists or the time is blocked.\n";

	public BlockCommandHandler(IUserInterface ui, String originalCommand, HashMap<AttributeType, String> attrList) {
		super(ui, originalCommand, attrList);
	}

	/**
	 * Needs to be explicitly called for the command to be started <br/>
	 * This method will first check for syntax error before executing the
	 * command <br/>
	 */
	public void start() {
		if (isSyntaxCorrect()) {
			execute();
		} else {
			pushCommandToHistory(CommandType.invalid);
			writeToConsole(SYNTAX_ERROR);
		}
	}

	/**
	 * Enforce the the taskName, startingTime and endngTime fields are properly
	 * provided<br/>
	 * 
	 * @return true if the syntax is correct. otherwise false (when the name is
	 *         null or one of the time cannot be parsed into Date type)
	 */
	private boolean isSyntaxCorrect() {
		String taskName = _attrList.get(AttributeType.name);
		DateTime startingTime = getDateTime(_attrList.get(AttributeType.startingTime));
		DateTime endingTime = getDateTime(_attrList.get(AttributeType.endingTime));

		if (taskName != null && startingTime != null && endingTime != null) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * Check for storage constraint when creating new Task <br/>
	 * The new Task cannot duplicate with any existing Task, and taskName must
	 * not be empty <br/>
	 * More important, the task cannot collide with blocked Task<br/>
	 * If the task itself is type "blocked", it cannot collide with any other
	 * Task <br/>
	 * 
	 * @param newTask
	 * @return false is no violation found, otherwise true
	 */
	private boolean isViolatingStorageConstraint(Database storage, Task newTask) {
		if (newTask.getName() == null || storage.isTaskExist(newTask)) {
			return true;
		}
		if (storage.isCollideWithExistingTask(newTask)) {
			return true;
		}

		return false;
	}

	/**
	 * Execute the command <br/>
	 * Create the timed task with the name, startingTime, endingTime and status
	 * set correctly <br/>
	 * <b>Note:</b> The syntax must be checked before calling execute <br/>
	 */
	private void execute() {
		// Assert: The syntax must be adhered first
		DateHelper dh = new DateHelper();
		assert (_attrList.get(AttributeType.name) != null);
		assert (dh.DateFormatter(_attrList.get(AttributeType.startingTime)) != null);
		assert (dh.DateFormatter(_attrList.get(AttributeType.endingTime)) != null);

		DateTime startDate = getDateTime(_attrList.get(AttributeType.startingTime));
		DateTime endDate = getDateTime(_attrList.get(AttributeType.endingTime));

		writeToStorage(_attrList.get(AttributeType.name), _attrList.get(AttributeType.description), startDate, endDate);
	}

	/**
	 * Create and write the Task into Storage <br/>
	 * Also push a record in History <br/>
	 * 
	 * @param name
	 *            the name of the Task written into the database
	 * @param description
	 *            the Task's description
	 * @param startDate
	 *            the Task's startingDate
	 * @param endDate
	 *            the Task's endingDate
	 */
	private void writeToStorage(String name, String description, DateTime startDate, DateTime endDate) {
		// The block task
		Task newTask = new Task(name, TaskType.timed, description, startDate, endDate, TaskStatus.block);

		if (!isViolatingStorageConstraint(getStorage(), newTask)) {
			boolean isCreated = getStorage().createTask(newTask);

			if (isCreated) {
				// Task created
				pushCommandToHistory(CommandType.add, newTask);
				writeToConsole(String.format(BLOCK_SUCCESSFUL, newTask.toString(true)));
			} else {
				// Create unsuccessful
				pushToHistoryAsNonExecutableCommand();
				writeToConsole(String.format(BLOCK_ERROR, newTask));
			}
		} else {
			// Violating storage constraint!
			pushToHistoryAsNonExecutableCommand();
			writeToConsole(String.format(CREATE_OR_COLLISION_EXIST, newTask));
		}
	}
}
